/*
 * Copyright (c) 2005 -2008 Reliable Source, Inc. and others.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Mozilla Public License v.1.1,
 * BSD, and Eclipse Public License v1.0 which accompanies this
 * distribution and is available at:
 *
 * 		http://www.eclipse.org/legal/epl-v10.html
 * 		http://www.opensource.org/licenses/bsd-license.php
 * 		http://www.mozilla.org/MPL/MPL-1.1.html
 *
 * Contributors:
 *     IBM Corporation	     -  http://ibm.com
 *     	- initial API and implementation
 *
 *     patientos.org         - http://patientos.org
 *     	- domain and database persistence layer
 *
 *     Reliable Source, Inc. - http://reliablesource.org
 *     	- Symbiosys Application Framework,
 *     	- Symbiosys Application, Symbiosys Product
 *
 */
package org.reliablesource.symbiosys.workbench.tests.menus;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;

import org.eclipse.jface.action.GroupMarker;
import org.eclipse.jface.action.IContributionItem;
import org.eclipse.jface.action.MenuManager;
import org.eclipse.jface.action.SubContributionItem;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.ISelectionChangedListener;
import org.eclipse.jface.viewers.ISelectionProvider;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.ui.IWorkbenchPage;
import org.eclipse.ui.IWorkbenchPart;
import org.eclipse.ui.IWorkbenchWindow;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.internal.PluginActionContributionItem;
import org.eclipse.ui.internal.PopupMenuExtender;
import org.eclipse.ui.tests.harness.util.UITestCase;
import org.reliablesource.symbiosys.workbench.tests.mockobjects.MockPerspective;

/**
 * 
 * SymbiosysObjectContributionTest.java<br>
 * Created on: Jun 27, 2008<br>
 *
 * @author <a href="mailto:dennis.park@gmail.com">Dennis Park</a>
 *
 * @category
 * @since 1.0
 */
abstract public class SymbiosysViewActionContributionTest extends UITestCase {
    protected IWorkbenchPage fPage;
    protected IWorkbenchWindow fWindow;

    public SymbiosysViewActionContributionTest(String testName) {
        super(testName);
    }

    /**
     * Helper class that will create a popup menu based on the given selection
     * and then ensure that the provided commandIds are added to the menu.
     *
     * @param commandIds
     *            the command ids that should appear in the menu
     * @param selection
     *            the selection on which to contribute object contributions
     */
    public void assertActionItemIsEnabled(String name, String[] commandIds,
        final ISelection selection, Class selectionType, boolean existance) {
        ISelectionProvider selectionProvider = new ISelectionProvider() {
                public void addSelectionChangedListener(
                    ISelectionChangedListener listener) {
                }

                public ISelection getSelection() {
                    return selection;
                }

                public void removeSelectionChangedListener(
                    ISelectionChangedListener listener) {
                }

                public void setSelection(ISelection selection) {
                }
            };

        // The popup extender needs a part to notify actions of the active part
        IWorkbenchPart part = fPage.getActivePartReference().getPart(true);

        // Create a fake PopupMenuExtender so we can get some data back.
        final MenuManager fakeMenuManager = new MenuManager();
        fakeMenuManager.add(new GroupMarker(
                org.eclipse.ui.IWorkbenchActionConstants.MB_ADDITIONS));

        final PopupMenuExtender extender = new PopupMenuExtender(null,
                fakeMenuManager, selectionProvider, part);

        extender.menuAboutToShow(fakeMenuManager);

        extender.dispose();

        Set seenCommands = new HashSet(Arrays.asList(commandIds));
        List commands = new ArrayList(Arrays.asList(commandIds));
        traverseMenu(fakeMenuManager, seenCommands, commands, selectionType,
            commandIds, name, existance, true);

        if (existance && !commands.isEmpty()) {
            fail(name + " Missing " + commands.toString() +
                " from context menu.");
        }
    }

    /**
     * Helper class that will create a popup menu based on the given selection
     * and then ensure that the provided commandIds are added to the menu.
     *
     * @param commandIds
     *            the command ids that should appear in the menu
     * @param selection
     *            the selection on which to contribute object contributions
     */
    public void assertActionItemIsDisabled(String name, String[] commandIds,
        final ISelection selection, Class selectionType, boolean existance) {
        ISelectionProvider selectionProvider = new ISelectionProvider() {
                public void addSelectionChangedListener(
                    ISelectionChangedListener listener) {
                }

                public ISelection getSelection() {
                    return selection;
                }

                public void removeSelectionChangedListener(
                    ISelectionChangedListener listener) {
                }

                public void setSelection(ISelection selection) {
                }
            };

        // The popup extender needs a part to notify actions of the active part
        final IWorkbenchPage page = PlatformUI.getWorkbench()
                                              .getActiveWorkbenchWindow()
                                              .getActivePage();
        IWorkbenchPart part = page.getActivePartReference().getPart(true);

        // Create a fake PopupMenuExtender so we can get some data back.
        final MenuManager fakeMenuManager = new MenuManager();
        fakeMenuManager.add(new GroupMarker(
                org.eclipse.ui.IWorkbenchActionConstants.MB_ADDITIONS));

        final PopupMenuExtender extender = new PopupMenuExtender(null,
                fakeMenuManager, selectionProvider, part);

        /*
         * Pretend to show the pop-up menu -- looking to motivate the extender
         * to fill the menu based on the selection provider.
         *
         * TODO This causes a big delay (in the order of a minute or more) while
         * trying to fill this menu. It seems to be loading a bunch of plug-ins,
         * and doing class loading.
         */
        extender.menuAboutToShow(fakeMenuManager);

        extender.dispose();

        // Check to see if the appropriate object contributions are present.
        final IContributionItem[] items = fakeMenuManager.getItems();
        Set seenCommands = new HashSet(Arrays.asList(commandIds));
        List commands = new ArrayList(Arrays.asList(commandIds));

        traverseMenu(fakeMenuManager, seenCommands, commands, selectionType,
            commandIds, name, existance, false);

        if (existance && !commands.isEmpty()) {
            fail(name + " Missing " + commands.toString() +
                " from context menu.");
        }
    }

    protected void traverseMenu(MenuManager _mgr, Set seenCommands,
        List commands, Class selectionType, String[] commandIds, String name,
        boolean existance, boolean checkEnabled) {
        //		 Check to see if the appropriate object contributions are present.
        final IContributionItem[] items = _mgr.getItems();

        for (int i = 0; i < items.length; i++) {
            IContributionItem contributionItem = items[i];

            // Step 1: test the selection
            if (selectionType != null) {
                IContributionItem item = contributionItem;

                int nCmds = commandIds.length;

                for (int j = 0; j < nCmds; j++) {
                    if (commandIds[j].equals(item.getId())) {
                        if (checkEnabled)
                            assertTrue(name + " selection not enabled",
                                item.isEnabled());
                        else
                            assertTrue(name + " selection not disabled",
                                !item.isEnabled());
                    }
                }

                if (item instanceof SubContributionItem) {
                    item = ((SubContributionItem) contributionItem).getInnerItem();
                }

                if (item instanceof MenuManager) {
                    traverseMenu((MenuManager) item, seenCommands, commands,
                        selectionType, commandIds, name, existance, checkEnabled);
                }

                if (item instanceof PluginActionContributionItem) {
                    // Verify that the selection passed to the action has been
                    // converted
                    ISelection s = null;

                    if (s instanceof IStructuredSelection) {
                        for (Iterator it = ((IStructuredSelection) s).iterator();
                                it.hasNext();) {
                            Object element = it.next();
                            assertTrue(name + " selection not converted",
                                selectionType.isInstance(element));
                        }
                    }
                }
            }

            // Step 2: remember that we saw this element
            String id = contributionItem.getId();

            if (existance) {
                boolean removed = commands.remove(id);

                if (seenCommands.contains(id) && !removed) {
                    fail(name + " item duplicated in the context menu: " + id);
                }
            } else {
                assertTrue(name + " item should not be in the context menu",
                    !commands.contains(id));
            }
        }
    }

    @Override
    protected void doSetUp() throws Exception {
        super.doSetUp();
        fPage = fWorkbench.getActiveWorkbenchWindow()
                          .openPage(getPerspectiveId(), null);
    }

    protected String getPerspectiveId() {
        return MockPerspective.ID;
    }

    //	public void testRemoveIsEnabled(){
    //		StructuredSelection _selection = new StructuredSelection(element);
    //		assertActionItemIsEnabled("dettach business tag",
    //				new String[] { DeleteBusObjAction.ID},
    //				_selection, _class, true);
    //	}
    //	
    //	public void testRemoveIsDisabled(){
    //		StructuredSelection _selection = new StructuredSelection(element);
    //		assertActionItemIsDisabled("dettach business tag",
    //				new String[] { DeleteBusObjAction.ID},
    //				_selection, _class, true);
    //	}
}
